﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Health;
using SDS.SPHealthAnalyzerRules.Delegation.Helpers;

namespace SDS.SPHealthAnalyzerRules.Delegation.Rules
{
    /// <summary>
    /// ensures that any Kerberos sites are configured to with the NTLM provider
    /// </summary>
    /// <remarks>
    /// When SPD opens, it calls /_vti_bin/Client.svc which uses ComponentModel, which REQUIRES NTLM.
    /// Without an NTLM provider, SPD will fail to connect to any site.
    /// </remarks>
    public class WebApps__Using_NTLM_AuthProvider : SPHealthAnalysisRule
    {
        private Guid CorrelationToken = Guid.NewGuid();

        [System.Diagnostics.DebuggerDisplay("{ServerName}/{WebAppName} using {AuthProviders}")]
        private struct Error
        {
            public string WebAppName;
            public string AuthProviders;
        }
        readonly private List<Error> Errors = new List<Error>();

        public override SPHealthCategory Category { get { return SPHealthCategory.Configuration; } }
        public override SPHealthCheckErrorLevel ErrorLevel { get { return SPHealthCheckErrorLevel.Error; } }

        public override SPHealthAnalysisRuleAutomaticExecutionParameters AutomaticExecutionParameters
        {
            get
            {
                return new SPHealthAnalysisRuleAutomaticExecutionParameters()
                {
                    Schedule = SPHealthCheckSchedule.Daily,
                    Scope = SPHealthCheckScope.All,
                    ServiceType = typeof(SPWebService),
                    RepairAutomatically = false
                };
            }
        }

        public override SPHealthCheckStatus Check()
        {
            // return variable, defualt value
            SPHealthCheckStatus outval = SPHealthCheckStatus.Failed;

            // log
            LoggingService.Write(LoggingService.Category_WebApp, TraceSeverity.Verbose, "Executing Health Check", CorrelationToken);

            // running as the system account
            Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(delegate { doCheck(); });

            // set return value
            outval = Errors.Count == 0
                 ? SPHealthCheckStatus.Passed
                 : SPHealthCheckStatus.Failed;

            // log
            LoggingService.Write(
                LoggingService.Category_WebApp,
                TraceSeverity.Verbose,
                String.Format("Health Check completed with outcome {0}", outval.ToString()),
                CorrelationToken);

            return outval;
        }

        public override string Summary { get { return "DELEGATION: Kerberos Web Applications are missing NTLM authentication provider."; } }
        public override string Explanation
        {
            get
            {
                var x = Errors.Select(e => String.Format(@"WebApp [{0}] using [{1}]",
                                                          e.WebAppName,
                                                          e.AuthProviders))
                              .ToArray();
                return String.Format(
                    @"{0}The following Web Applications are configured for Kerberos authentication, but do not include the NTLM authentication provider:" +
                    @"{0}" +
                    @"{0}The NTLM authentication provider is required by SharePoint Designer." +
                    @"{0}" +
                    @"{0}{1}",
                    Environment.NewLine,
                    String.Join(Environment.NewLine, x));
            }
        }
        public override string Remedy
        {
            get { return String.Format("Either disable Kerberos authentication, or configure the IIS site to include the NTLM authentication provider."); }
        }




        public void doCheck()
        {
            try
            {

                // if current server is running SPWebService (web apps)
                var Server = Microsoft.SharePoint.Administration.SPServer.Local;
                if (Server.isRunning<SPWebService>())
                {
                    // looking for webapps using kerberos
                    Server.WebApplications()
                          .UsingKerberos()
                          .Select(wa => new { WebApp = wa, AuthProviders = wa.WindowsAuthenticationProviders() })
                          .Where(x => !x.AuthProviders.Contains("NTLM"))
                          .ToList()
                          .ForEach(x =>
                          {
                              Errors.Add(new Error()
                              {
                                  WebAppName = x.WebApp.DisplayName,
                                  AuthProviders = String.Join(", ", x.AuthProviders.ToArray())
                              });
                          });

                } // FOREACH Server

            } // try
            catch (Exception ex)
            {
                LoggingService.Write(
                    LoggingService.Category_WebApp,
                    TraceSeverity.High,
                    String.Format("Health Check encountered the following exception: {0}", ex.Message),
                    CorrelationToken);
            }

        } // doCheck()

    }
}
